package moe.codeest.enviews;

import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.*;
import ohos.agp.utils.Color;
import ohos.agp.utils.Point;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;

/**
 * Created by codeest on 16/11/13.
 * <p>
 * 嗯..这个控件很带感 隔着屏幕都能感受到声音有木有~
 */

public class ENVolumeView extends Component implements Component.DrawTask, Component.LayoutRefreshedListener {

    private static final int STATE_SILENT = 0;

    private static final int STATE_VOLUME = 1;

    private static final int STATE_VIBRATE = 2;

    private static final int DEFAULT_LINE_COLOR = 0xffffffff;

    private static final int DEFAULT_BG_LINE_COLOR = 0xff64696d;

    private static final int DEFAULT_LINE_WIDTH = 10;

    private static final int DEFAULT_BG_LINE_WIDTH = 10;

    private Paint mPaint, mBgPaint;

    private Path mPath, mDstPath;

    private PathMeasure mPathMeasure;

    private float mFraction;

    private int mVolumeValue;

    private float mCurrentState = STATE_SILENT;

    private float mWidth, mHeight;

    private float mCenterX, mCenterY;

    private float mBaseLength, mPathLength;

    private AnimatorValue vibrateAnim;

    private boolean isInit = false;

    public ENVolumeView(Context context) {
        this(context, null);
    }

    public ENVolumeView(Context context, AttrSet attrSet) {
        this(context, attrSet, null);
    }

    public ENVolumeView(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        int lineColor = AttrUtils.getColorFromAttr(attrSet, "volume_line_color", DEFAULT_LINE_COLOR);
        int lineWidth = AttrUtils.getDimensionFromAttr(attrSet, "volume_line_width", DEFAULT_LINE_WIDTH);
        int bgLineColor = AttrUtils.getColorFromAttr(attrSet, "volume_bg_line_color", DEFAULT_BG_LINE_COLOR);
        int bgLineWidth = AttrUtils.getDimensionFromAttr(attrSet, "volume_bg_line_width", DEFAULT_BG_LINE_WIDTH);

        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.STROKE_STYLE);
        mPaint.setStrokeCap(Paint.StrokeCap.ROUND_CAP);
        mPaint.setStrokeJoin(Paint.Join.ROUND_JOIN);
        mPaint.setColor(new Color(lineColor));
        mPaint.setStrokeWidth(lineWidth);

        mBgPaint = new Paint();
        mBgPaint.setAntiAlias(true);
        mBgPaint.setStyle(Paint.Style.STROKE_STYLE);
        mBgPaint.setStrokeCap(Paint.StrokeCap.ROUND_CAP);
        mBgPaint.setStrokeJoin(Paint.Join.ROUND_JOIN);
        mBgPaint.setColor(new Color(bgLineColor));
        mBgPaint.setStrokeWidth(bgLineWidth);

        mPath = new Path();
        mDstPath = new Path();
        mPathMeasure = new PathMeasure(mPath, false);

        addDrawTask(this);
        setLayoutRefreshedListener(this);
    }

    private void onRefreshed(int w, int h) {
        mWidth = w * 5 / 6;
        mHeight = h;
        mBaseLength = mWidth / 6;
        mCenterX = w / 2;
        mCenterY = h / 2;

        mPath.moveTo(mCenterX - 3 * mBaseLength, mCenterY);
        mPath.lineTo(mCenterX - 3 * mBaseLength, mCenterY - 0.5f * mBaseLength);
        mPath.lineTo(mCenterX - 2 * mBaseLength, mCenterY - 0.5f * mBaseLength);
        mPath.lineTo(mCenterX, mCenterY - 2 * mBaseLength);
        mPath.lineTo(mCenterX, mCenterY + 2 * mBaseLength);
        mPath.lineTo(mCenterX - 2 * mBaseLength, mCenterY + 0.5f * mBaseLength);
        mPath.lineTo(mCenterX - 3 * mBaseLength, mCenterY + 0.5f * mBaseLength);
        mPath.close();
        mPathMeasure.setPath(mPath, false);
        mPathLength = mPathMeasure.getLength();

    }

    @Override
    public void onRefreshed(Component component) {
        onRefreshed(component.getWidth(), component.getHeight());
        vibrateAnim = new AnimatorValue();
        vibrateAnim.setDuration(200);
        vibrateAnim.setCurveType(Animator.CurveType.LINEAR);
        vibrateAnim.setLoopedCount(Animator.INFINITE);
        vibrateAnim.setValueUpdateListener((animatorValue, v) -> {
            if (v < 0.5) {
                mFraction = v * 2;
            } else {
                mFraction = (1 - v) * 2;
            }
            invalidate();
        });
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        if (!isInit) {
            isInit = true;
            onRefreshed(component.getWidth(), component.getHeight());
        }
        if (mCurrentState != STATE_VIBRATE) {
            if (mFraction <= 0.5) {
                mDstPath.reset();   //嗷~ 在这画喇叭
                mPathMeasure.getSegment(0, mPathLength * 0.38f - mPathLength * 0.13f * mFraction, mDstPath, true);
                canvas.drawPath(mDstPath, mBgPaint);
                mDstPath.reset();
                mPathMeasure.getSegment(mPathLength * 0.62f + mPathLength * 0.13f * mFraction, mPathLength, mDstPath, true);
                canvas.drawPath(mDstPath, mBgPaint);

                canvas.save();  //嗷~ 在这画X
                canvas.translate(-mFraction * mBaseLength * 2, 0);
                canvas.drawLine(mCenterX - mBaseLength * (0.5f - mFraction), mCenterY - mBaseLength * (0.5f - mFraction)
                        , mCenterX + mBaseLength * (0.5f - mFraction), mCenterY + mBaseLength * (0.5f - mFraction), mBgPaint);
                canvas.drawLine(mCenterX - mBaseLength * (0.5f - mFraction), mCenterY + mBaseLength * (0.5f - mFraction)
                        , mCenterX + mBaseLength * (0.5f - mFraction), mCenterY - mBaseLength * (0.5f - mFraction), mBgPaint);
                canvas.restore();
            } else {
                mDstPath.reset();   //嗷~ 在这画喇叭
                mPathMeasure.getSegment(0, mPathLength * 0.25f + mPathLength * 0.13f * (mFraction - 0.5f), mDstPath, true);
                canvas.drawPath(mDstPath, mBgPaint);
                mDstPath.reset();
                mPathMeasure.getSegment(mPathLength * 0.75f - mPathLength * 0.13f * (mFraction - 0.5f), mPathLength, mDstPath, true);
                canvas.drawPath(mDstPath, mBgPaint);
                mDstPath.reset();
                mPathMeasure.getSegment(0, mPathLength * 0.38f / 0.5f * (mFraction - 0.5f), mDstPath, true);
                canvas.drawPath(mDstPath, mPaint);
                mDstPath.reset();
                mPathMeasure.getSegment(mPathLength - mPathLength * 0.38f / 0.5f * (mFraction - 0.5f), mPathLength, mDstPath, true);
                canvas.drawPath(mDstPath, mPaint);

                canvas.save();  //嗷~ 在这画小声波
                canvas.translate(-(1 - mFraction) * mBaseLength * 2, 0);
                canvas.drawArc(new RectFloat(mCenterX - 0.5f * mBaseLength - mBaseLength / 0.5f * (mFraction - 0.5f),
                        mCenterY - mBaseLength / 0.5f * (mFraction - 0.5f),
                        mCenterX - 0.5f * mBaseLength + mBaseLength / 0.5f * (mFraction - 0.5f),
                        mCenterY + mBaseLength / 0.5f * (mFraction - 0.5f)), new Arc(-55, 110, false), mBgPaint);
                int sVolume = mVolumeValue;
                if (sVolume > 50)
                    sVolume = 50;
                canvas.drawArc(new RectFloat(mCenterX - 0.5f * mBaseLength - mBaseLength / 0.5f * (mFraction - 0.5f),
                        mCenterY - mBaseLength / 0.5f * (mFraction - 0.5f),
                        mCenterX - 0.5f * mBaseLength + mBaseLength / 0.5f * (mFraction - 0.5f),
                        mCenterY + mBaseLength / 0.5f * (mFraction - 0.5f)), new Arc(-55 / 50 * sVolume, 110 / 50 * sVolume, false), mPaint);
                canvas.restore();

                canvas.save();  //嗷~ 在这画大声波
                canvas.translate(-(1 - mFraction) * mBaseLength * 3, 0);
                canvas.drawArc(new RectFloat(mCenterX - 1.6f * mBaseLength / 0.5f * (mFraction - 0.5f),
                        mCenterY - 1.6f * mBaseLength / 0.5f * (mFraction - 0.5f),
                        mCenterX + 1.6f * mBaseLength / 0.5f * (mFraction - 0.5f),
                        mCenterY + 1.6f * mBaseLength / 0.5f * (mFraction - 0.5f)), new Arc(-55, 110, false), mBgPaint);
                int lVolume = mVolumeValue - 50;
                if (lVolume < 0)
                    lVolume = 0;
                canvas.drawArc(new RectFloat(mCenterX - 1.6f * mBaseLength / 0.5f * (mFraction - 0.5f),
                        mCenterY - 1.6f * mBaseLength / 0.5f * (mFraction - 0.5f),
                        mCenterX + 1.6f * mBaseLength / 0.5f * (mFraction - 0.5f),
                        mCenterY + 1.6f * mBaseLength / 0.5f * (mFraction - 0.5f)), new Arc(-55 / 50 * lVolume, 110 / 50 * lVolume, false), mPaint);
                canvas.restore();
            }
        } else {
            mDstPath.reset();   //嗷~ 在这画喇叭
            mPathMeasure.getSegment(0, mPathLength * 0.38f, mDstPath, true);
            canvas.drawPath(mDstPath, mPaint);
            mDstPath.reset();
            mPathMeasure.getSegment(mPathLength - mPathLength * 0.38f, mPathLength, mDstPath, true);
            canvas.drawPath(mDstPath, mPaint);

            canvas.save();  //嗷~ 在这画小声波
            canvas.translate(-(1 - mFraction) * mBaseLength / 5 * 2 * mVolumeValue / 100, 0);
            canvas.drawArc(new RectFloat(mCenterX - 1.5f * mBaseLength,
                    mCenterY - mBaseLength,
                    mCenterX + 0.5f * mBaseLength,
                    mCenterY + mBaseLength), new Arc(-55, 110, false), mBgPaint);
            int sVolume = mVolumeValue;
            if (sVolume > 50)
                sVolume = 50;
            canvas.drawArc(new RectFloat(mCenterX - 1.5f * mBaseLength,
                    mCenterY - mBaseLength,
                    mCenterX + 0.5f * mBaseLength,
                    mCenterY + mBaseLength), new Arc(-55 / 50 * sVolume, 110 / 50 * sVolume, false), mPaint);
            canvas.restore();

            canvas.save();  //嗷~ 在这画大声波
            canvas.translate(-(1 - mFraction) * mBaseLength / 5 * 2 * mVolumeValue / 100, 0);
            canvas.drawArc(new RectFloat(mCenterX - 1.6f * mBaseLength,
                    mCenterY - 1.6f * mBaseLength,
                    mCenterX + 1.6f * mBaseLength,
                    mCenterY + 1.6f * mBaseLength), new Arc(-55, 110, false), mBgPaint);
            int lVolume = mVolumeValue - 50;
            if (lVolume < 0)
                lVolume = 0;
            canvas.drawArc(new RectFloat(mCenterX - 1.6f * mBaseLength,
                    mCenterY - 1.6f * mBaseLength,
                    mCenterX + 1.6f * mBaseLength,
                    mCenterY + 1.6f * mBaseLength), new Arc(-55 / 50 * lVolume, 110 / 50 * lVolume, false), mPaint);
            canvas.restore();
        }
    }

    private void closeVolume() {
        AnimatorValue animatorValue = new AnimatorValue();
        animatorValue.setDuration(800);
        animatorValue.setCurveType(Animator.CurveType.ACCELERATE_DECELERATE);
        animatorValue.setValueUpdateListener((animatorValue1, v) -> {
            mFraction = 1 - v;
            invalidate();
        });
        if (!animatorValue.isRunning()) {
            animatorValue.start();
        }
    }

    private void openVolume() {
        AnimatorValue animatorValue = new AnimatorValue();
        animatorValue.setDuration(800);
        animatorValue.setCurveType(Animator.CurveType.LINEAR);
        animatorValue.setValueUpdateListener((animatorValue1, v) -> {
            mFraction = v;
            invalidate();
        });
        animatorValue.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {

            }

            @Override
            public void onStop(Animator animator) {

            }

            @Override
            public void onCancel(Animator animator) {

            }

            @Override
            public void onEnd(Animator animator) {
                if (mVolumeValue == 0) {
                    closeVolume();
                } else {
                    startVibration();
                }
            }

            @Override
            public void onPause(Animator animator) {

            }

            @Override
            public void onResume(Animator animator) {

            }
        });
        if (!animatorValue.isRunning()) {
            animatorValue.start();
        }
    }

    private void startVibration() {
        mCurrentState = STATE_VIBRATE;
        if (!vibrateAnim.isRunning()) {
            vibrateAnim.start();
        }
    }

    private void stopVibration() {
        if (vibrateAnim.isRunning()) {
            vibrateAnim.cancel();
        }
    }

    public void updateVolumeValue(int value) {
        if (value < 0 || value > 100) {
            return;
        }
        mVolumeValue = value;
        if (value == 0 && mCurrentState != STATE_SILENT) {
            mCurrentState = STATE_SILENT;
            stopVibration();
            closeVolume();
        } else if (value != 0 && mCurrentState == STATE_SILENT) {
            mCurrentState = STATE_VOLUME;
            openVolume();
        }
    }
}
